﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SimpleGameData.GameObjects.Particles;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SimpleGame.Utils;
using System.Diagnostics;

namespace SimpleGame.GameObjects.Particles
{
    public class Emitter
    {
        #region Fields

        // The emitter data read from a xml file
        private EmitterData emitterData;
        // List of particles this emitter "has"
        private List<Particle> particles;
        // List of particles to add to the main list. Needed to add and remove particles on runtime.
        private List<Particle> particlesToAdd;

        #endregion

        #region Properties

        /// <summary>
        /// The emitter data read from a xml file
        /// </summary>
        public EmitterData EmitterData
        {
            get { return emitterData; }
            set { emitterData = value; }
        }

        /// <summary>
        /// List of particles this emitter has available
        /// </summary>
        public List<Particle> Particles
        {
            get { return particles; }
            set { particles = value; }
        }

        #endregion

        #region Constructor

        public Emitter()
        {
            particles = new List<Particle>();
            particlesToAdd = new List<Particle>();
        }

        #endregion

        #region General Methods

        /// <summary>
        /// Adds an amount of "empty" particles to the emitter
        /// </summary>
        /// <param name="x">The amount of particles to add</param>
        public void AddParticles(int x)
        {
            for (int i = 0; i < x; i++)
            {
                Particle particle = new Particle();

                particle.Texture = emitterData.Texture;
                particle.Position = emitterData.EmitterPosition;
                particle.IsRotationDirectionRandom = emitterData.IsRotationDirectionRandom;
                particle.IsRotationClockWise = emitterData.IsRotationClockwise;
                particle.EmissionAngle = RandomGenerator.Float(
                    emitterData.EmissionAngle.MinValue,
                    emitterData.EmissionAngle.MaxValue);
                particle.LifeTime = RandomGenerator.Float(
                    emitterData.LifeMinMax.MinValue, 
                    emitterData.LifeMinMax.MaxValue);
                particle.Velocity = RandomGenerator.Float(
                    emitterData.VelocityMinMax.MinValue,
                    emitterData.VelocityMinMax.MaxValue);
                particle.Acceleration = RandomGenerator.Float(
                    emitterData.AccelerationMinMax.MinValue,
                    emitterData.AccelerationMinMax.MaxValue);
                particle.Rotation = RandomGenerator.Float(
                    emitterData.RotationMinMax.MinValue,
                    emitterData.RotationMinMax.MaxValue);
                particle.RotationSpeed = RandomGenerator.Float(
                    emitterData.RotationSpeedMinMax.MinValue,
                    emitterData.RotationSpeedMinMax.MaxValue);
                particle.Scale = RandomGenerator.Float(
                    emitterData.ScaleMinMax.MinValue,
                    emitterData.ScaleMinMax.MaxValue);
                particle.ScaleShift = RandomGenerator.Float(
                    emitterData.ScaleShiftMinMax.MinValue,
                    emitterData.ScaleShiftMinMax.MaxValue);
                particle.ColorRedStart = RandomGenerator.Float(
                    emitterData.ColorRedStartMinMax.MinValue,
                    emitterData.ColorRedStartMinMax.MaxValue);
                particle.ColorRedEnd = RandomGenerator.Float(
                    emitterData.ColorRedEndMinMax.MinValue,
                    emitterData.ColorRedEndMinMax.MaxValue);
                particle.ColorGreenStart = RandomGenerator.Float(
                    emitterData.ColorGreenStartMinMax.MinValue,
                    emitterData.ColorGreenStartMinMax.MaxValue);
                particle.ColorGreenEnd = RandomGenerator.Float(
                    emitterData.ColorGreenEndMinMax.MinValue,
                    emitterData.ColorGreenEndMinMax.MaxValue);
                particle.ColorBlueStart = RandomGenerator.Float(
                    emitterData.ColorBlueStartMinMax.MinValue,
                    emitterData.ColorBlueStartMinMax.MaxValue);
                particle.ColorBlueEnd = RandomGenerator.Float(
                    emitterData.ColorBlueEndMinMax.MinValue,
                    emitterData.ColorBlueEndMinMax.MaxValue);
                particle.AlphaValueStart = RandomGenerator.Float(
                    emitterData.AlphaValueStartMinMax.MinValue,
                    emitterData.AlphaValueStartMinMax.MaxValue);
                particle.AlphaValueEnd = RandomGenerator.Float(
                    emitterData.AlphaValueEndMinMax.MinValue,
                    emitterData.AlphaValueEndMinMax.MaxValue);

                particlesToAdd.Add(particle);
            }
        }

        /// <summary>
        /// Removes an amount of particles from the emitter
        /// </summary>
        /// <param name="x">The amount of particles to remove </param>
        public void RemoveParticles(int x)
        {
            for (int i = 0; i < x; i++)
            {
                particles.RemoveAt(particles.Count - 1);
            }
        }

        /// <summary>
        /// Updates the amount of particles.
        /// </summary>
        public void UpdateParticleCount()
        {
            int x = Math.Abs(emitterData.ParticleCount - particles.Count);
            if (emitterData.ParticleCount < particles.Count - 1)
            {
                RemoveParticles(x);
            }
            else if (emitterData.ParticleCount > particles.Count - 1)
            {
                AddParticles(x);
            }
        }

        /// <summary>
        /// Updates every particles data to ensure it's up-to-date.
        /// </summary>
        public void UpdateParticleData()
        {

            foreach (Particle particle in particles)
            {
                if (!particle.IsAlive)
                {
                    particle.Position = emitterData.EmitterPosition;
                }
                particle.Texture = emitterData.Texture;
                particle.IsRotationDirectionRandom = emitterData.IsRotationDirectionRandom;
                particle.IsRotationClockWise = emitterData.IsRotationClockwise;
                particle.EmissionAngle = RandomGenerator.Float(
                    emitterData.EmissionAngle.MinValue,
                    emitterData.EmissionAngle.MaxValue);
                particle.LifeTime = RandomGenerator.Float(
                    emitterData.LifeMinMax.MinValue,
                    emitterData.LifeMinMax.MaxValue);
                particle.Velocity = RandomGenerator.Float(
                    emitterData.VelocityMinMax.MinValue,
                    emitterData.VelocityMinMax.MaxValue);
                particle.Acceleration = RandomGenerator.Float(
                    emitterData.AccelerationMinMax.MinValue,
                    emitterData.AccelerationMinMax.MaxValue);
                particle.Rotation = RandomGenerator.Float(
                    emitterData.RotationMinMax.MinValue,
                    emitterData.RotationMinMax.MaxValue);
                particle.RotationSpeed = RandomGenerator.Float(
                    emitterData.RotationSpeedMinMax.MinValue,
                    emitterData.RotationSpeedMinMax.MaxValue);
                particle.Scale = RandomGenerator.Float(
                    emitterData.ScaleMinMax.MinValue,
                    emitterData.ScaleMinMax.MaxValue);
                particle.ScaleShift = RandomGenerator.Float(
                    emitterData.ScaleShiftMinMax.MinValue,
                    emitterData.ScaleShiftMinMax.MaxValue);
                particle.ColorRedStart = RandomGenerator.Float(
                    emitterData.ColorRedStartMinMax.MinValue,
                    emitterData.ColorRedStartMinMax.MaxValue);
                particle.ColorRedEnd = RandomGenerator.Float(
                    emitterData.ColorRedEndMinMax.MinValue,
                    emitterData.ColorRedEndMinMax.MaxValue);
                particle.ColorGreenStart = RandomGenerator.Float(
                    emitterData.ColorGreenStartMinMax.MinValue,
                    emitterData.ColorGreenStartMinMax.MaxValue);
                particle.ColorGreenEnd = RandomGenerator.Float(
                    emitterData.ColorGreenEndMinMax.MinValue,
                    emitterData.ColorGreenEndMinMax.MaxValue);
                particle.ColorBlueStart = RandomGenerator.Float(
                    emitterData.ColorBlueStartMinMax.MinValue,
                    emitterData.ColorBlueStartMinMax.MaxValue);
                particle.ColorBlueEnd = RandomGenerator.Float(
                    emitterData.ColorBlueEndMinMax.MinValue,
                    emitterData.ColorBlueEndMinMax.MaxValue);
                particle.AlphaValueStart = RandomGenerator.Float(
                    emitterData.AlphaValueStartMinMax.MinValue,
                    emitterData.AlphaValueStartMinMax.MaxValue);
                particle.AlphaValueEnd = RandomGenerator.Float(
                    emitterData.AlphaValueEndMinMax.MinValue,
                    emitterData.AlphaValueEndMinMax.MaxValue);
            }
        }

        #endregion

        #region Update Method

        public void Update(GameTime gameTime)
        {
            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

            int spawnCount = 0;

            foreach (Particle particle in particles)
            {
                // if particle is not alive anymore reuse the particle by randomizing its fields and setting it to alive again
                if (spawnCount < emitterData.ParticleMaxSpawnCount && !particle.IsAlive)
                {
                    particle.Position = emitterData.EmitterPosition;
                    particle.ResetAndSpawn();

                    spawnCount++;
                }

                particle.Update(gameTime);
            }

            particles.AddRange(particlesToAdd);
            particlesToAdd.Clear();
        }

        #endregion

        #region Draw Method

        public void Draw(SpriteBatch spriteBatch)
        {
            foreach (Particle particle in particles)
            {
                particle.Draw(spriteBatch);
            }
        }

        #endregion
    }
}
